package ar.uade.fain.ai.tpo.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import ar.uade.fain.ai.tpo.dao.ClienteDAO;
import ar.uade.fain.ai.tpo.dao.ComidaDAO;
import ar.uade.fain.ai.tpo.dao.PedidoDAO;
import ar.uade.fain.ai.tpo.dto.PedidoDTO;
import ar.uade.fain.ai.tpo.model.Cliente;
import ar.uade.fain.ai.tpo.model.Comida;
import ar.uade.fain.ai.tpo.model.ItemPedido;
import ar.uade.fain.ai.tpo.model.Pedido;
import ar.uade.fain.ai.tpo.model.Seccion;
import ar.uade.fain.ai.tpo.model.SeccionMemento;
import ar.uade.fain.ai.tpo.model.exceptions.SinStockException;
import ar.uade.fain.ai.tpo.model.politicas.PoliticaCompuesta;
import ar.uade.fain.ai.tpo.model.politicas.PoliticaDeClienteFrecuente;
import ar.uade.fain.ai.tpo.model.politicas.PoliticaDeComplejidadYAlHorno;
import ar.uade.fain.ai.tpo.model.politicas.PoliticaDeEnsalada;

public class AdministracionPedidoControlador implements Controlador {
	
	private ClienteDAO clienteDAO;
	private PedidoDAO pedidoDAO;
	private PoliticaCompuesta politicaPrecio;

	public AdministracionPedidoControlador() {
		super();
		
	}

	public PedidoDAO getPedidoDAO() {
		return pedidoDAO;
	}

	public void setPedidoDAO(PedidoDAO pedidoDAO) {
		this.pedidoDAO = pedidoDAO;
	}

	@Override
	public void init() {
		this.politicaPrecio=  new PoliticaCompuesta();
		this.politicaPrecio.agregarPolitica(new PoliticaDeClienteFrecuente());
		this.politicaPrecio.agregarPolitica(new PoliticaDeComplejidadYAlHorno());
		this.politicaPrecio.agregarPolitica(new PoliticaDeEnsalada());
	}

	@Override
	public void destroy() {
	}

	public synchronized Long altaPedido(PedidoDTO pedidoDTO) throws RuntimeException {

		List<Long> idComidas = pedidoDTO.getIdcomidas();
		List<Integer> cantComidas = pedidoDTO.getCantComidas();
		
		Long idCliente = pedidoDTO.getIdCliente();
		Cliente cliente = obtenerCliente(idCliente);
		// aca realizo la busqueda de la comida si existen o no

		List<ItemPedido> itemPedidos = agregarAItemPedidos(idComidas,
				cantComidas);

		Map<Seccion, SeccionMemento> mementosPorSeccion = this
				.obtenerSeccion(itemPedidos);
		try {
			for (ItemPedido ip : itemPedidos) {
				Comida comida = ip.getComida();
				int cantidad = ip.getCantidad();
				comida.getSeccion().preparar(comida, cantidad);
			}
		} catch (SinStockException e) {
			restaurarSecciones(mementosPorSeccion);
			String msj = "no se puede generar el pedido por falta de stock por falta de"
					+ e.getProducto().getNombre();
			System.err.println(msj);
			throw new RuntimeException(msj);
		}

		Pedido pedido = new Pedido(null, cliente);
		pedido.setItems(itemPedidos);
		this.pedidoDAO.guardar(pedido);
		
		return pedido.getId();
	}

	private Cliente obtenerCliente(Long idCliente) {
		Cliente cliente = clienteDAO.getByID(idCliente);
		
		if (cliente == null){
			throw new IllegalArgumentException("No existe el cliente Solicitado");
		}
		return cliente;
	}
	
	public Double obtenerPrecioPedido (PedidoDTO pedidoDTO){
		List<Long> idComidas = pedidoDTO.getIdcomidas();
		List<Integer> cantComidas = pedidoDTO.getCantComidas();
		List<ItemPedido> itemPedidos = agregarAItemPedidos(idComidas,cantComidas);
		Long idCliente = pedidoDTO.getIdCliente();
		Cliente cliente = obtenerCliente(idCliente);
		
		Pedido pedido = new Pedido(null, cliente);
		pedido.setItems(itemPedidos);
		pedido.calcularPrecio(politicaPrecio);
		
		return pedido.getPrecio();

	}



	private List<ItemPedido> agregarAItemPedidos(List<Long> idComidas,
			List<Integer> cantComidas) {
		ComidaDAO comidaDAO = new ComidaDAO();
		List<ItemPedido> itemPedidos = new ArrayList<ItemPedido>();
		for (int i = 0; i < idComidas.size(); i++) {
			Comida comida = comidaDAO.getByID(idComidas.get(i));

			itemPedidos.add(new ItemPedido(cantComidas.get(i), comida, null));

		}
		return itemPedidos;
	}

	private Map<Seccion, SeccionMemento> obtenerSeccion(
			List<ItemPedido> itemPedidos) {
		Set<Seccion> seccionesIP = new HashSet<Seccion>();
		for (ItemPedido ip : itemPedidos) {
			seccionesIP.add(ip.getComida().getSeccion());
		}
		Map<Seccion, SeccionMemento> mementos = new HashMap<Seccion, SeccionMemento>();
		for (Seccion s : seccionesIP) {
			SeccionMemento memento = s.crearMemento();
			mementos.put(s, memento);
		}
		return mementos;
	}

	private void restaurarSecciones(
			Map<Seccion, SeccionMemento> mementosPorSeccion) {
		for (Seccion s : mementosPorSeccion.keySet()) {
			s.restaurar(mementosPorSeccion.get(s));
		}

	}

	public ClienteDAO getClienteDAO() {
		return clienteDAO;
	}

	public void setClienteDAO(ClienteDAO clienteDAO) {
		this.clienteDAO = clienteDAO;
	}

	public PoliticaCompuesta getPoliticaPrecio() {
		return politicaPrecio;
	}

	public void setPoliticaPrecio(PoliticaCompuesta politicaPrecio) {
		this.politicaPrecio = politicaPrecio;
	}
	
}
